<?php

/** 
 * @author sifat
 * 
 * 
 */
class Db extends PDO{
	
	//public $query;
        private $_where;
        private $_query;
        private $_bindParam=array();
        private static $db;
	
	private function __clone()
	{
            
	}
	
	/**
	 * closing open connection
	 */
	function __destruct()
	{
		self :: $db=NULL;
	}
	/**
	 * making singleton
	 */	
	public static function getInstance()
	{
		if (self :: $db==NULL)
		{
			self :: $db = new Db("mysql:host=".HOST.";dbname=".DBNAME."", USERNAME, PASS, array(PDO::ATTR_PERSISTENT => true));
                        self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		}

		return self :: $db;
	}

        /*
         * select from db and return result set in an ASSOC array
         *
         */

        function select($tableName, $fields=array()){
            $this->selectStatement($tableName, $fields);
            $result=  $this->_exeQuery();
            return $result->fetchAll(PDO::FETCH_ASSOC);
            
        }
        /*
         * insert into db and returns insert id
         */
        function insert($tableName, $parameters=array()){
            if(empty ($parameters)){
                return FALSE;
            }
            $this->insertStetment($tableName, $parameters);
            $this->_exeQuery();
            return $this->lastInsertId();
        }

        /*
         * delete form db
         */

        function delete($tableName){
            
            $this->deleteStetment($tableName);
            $this->_exeQuery();
        }

        /*
         * generete delete query and returns query
         */

        function deleteStetment($tableName){
            $this->_query="DELETE FROM $tableName";

            if($this->_where){
                $this->_processWhere();
            }
            
            return $this->_query;
        }

        /*
         * generates insert query and returns the query
         */

        function insertStetment($tableName, $parameters){
            $i=0;
            $size=count($parameters);
            //$this->_bindParam=array();
            $this->_query='INSERT INTO '.$tableName.' (' ;
            foreach ($parameters as $key=>$value){
                $this->_query .= $key;
                if(++$i < $size){
                    $this->_query .= ',';
                }
                
                $this->_bindParam=array_merge($this->_bindParam, array($value));
            }
            $this->_query.=') VALUES (';
            
            $i=0;
            foreach ($parameters as $k=>$v){
                $this->_query.='?';
                if(++$i < $size){
                    $this->_query .= ',';
                }
            }
            $this->_query.=')';

            return $this->_query;
        }

        /*
         * update
         */

        function update($tableName, $fields=array()){
            if(empty ($fields) || empty ($this->_where)){
                return FALSE;
            }
            $this->updateStatememnt($tableName, $fields);
            $this->_exeQuery();
        }

        /*
         * generates update statement and returns the query
         */

        function updateStatememnt($tableName, $fields){
            $this->_query="UPDATE $tableName SET ";
            $size=count($fields);
            $i=0;
            foreach($fields as $key=>$value){
                $this->_query.=$key;
                $this->_query .='=';

                $this->_query.='?';
                if(++$i<$size){
                    $this->_query.=',';
                }
                $this->_bindParam=array_merge($this->_bindParam, array($value));
               
            }
            $this->_processWhere();
            return $this->_query;
        }

        function where($arr=array()){
            if(empty ($arr)){
                return $this;
            }
            $this->_where=$arr;
                       
            return $this;
        }

        function selectStatement($tableName, $fields=array()){
            $fields=empty ($fields) ? '*' : implode(",", $fields);
            $this->_query ="SELECT ";
            $this->_query .= $fields;
            $this->_query .= " FROM ";
            $this->_query .=$tableName;
            
            if($this->_where){
                $this->_processWhere();
               
            }
            return $this->_query;
        }

        private function _processWhere(){
            $this->_query.=" WHERE ";

            if(array_key_exists("OR", $this->_where)){
                $cons['OR']=$this->_where["OR"];
                unset ($this->_where["OR"]);
            }
            
            $cons['AND']=array_key_exists("AND", $this->_where)===TRUE?$this->_where["AND"]:  $this->_where;
           
            $j=0;
            foreach ($cons as $key=>$value){
                
                switch ($key) {
                
                    case "OR":
                        $i=0;
                        if($j++!=0 && $i==0){
                                $this->_query.=' OR ';
                            }
                        $size=count($cons["OR"]);
                        foreach($value as $k=>$v){
                            
                            $this->andOr($k, $v);
                            if(++$i < $size){
                                $this->_query.=' OR ';
                            }

                        }
                        break;

                    case "AND":
                    default:
                        $i=0;
                        $size=count($cons["AND"]);
                        foreach($value as $k=>$v){
                            if($j++!=0 && $i==0){
                                $this->_query.=' AND ';
                            }
                            $this->andOr($k, $v);
                            if(++$i < $size){
                                $this->_query.=' AND ';
                            }

                        }
                        break;
                }
            }
            unset ($this->_where);

        }

        function oparator($str){
            $str=trim($str);
            $oparator='';
            preg_match_all("/<|>|!|=/", $str, $matchs);

            if(empty ($matchs[0])){
                return '=';
            }
            foreach($matchs[0] as $match){
                $oparator.=$match;
            }
            
            return $oparator;
        }

        function andOr($k, $v){
            
            $conStr=trim(substr($k, 0, strpos($k, $this->oparator($k))))==NULL ? $k : trim(substr($k, 0, strpos($k, $this->oparator($k))));
            
            $this->_query.=$conStr;
            $this->_query.=$this->oparator($k);
            $this->_query.='?';
            $this->_bindParam=array_merge($this->_bindParam, array($v));
        }

        /*
         * prepare and executes query
         */
        private function _exeQuery(){
            $sth=$this->prepare($this->_query);
            foreach ($this->_bindParam as $key=>$value){
                $sth->bindValue(++$key, $value);
            }
            $sth->execute();
            $this->_bindParam=array();
            return $sth;
        }

}